package xfuzzy.alg_genetico.indeterminado.population;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import xfuzzy.xfghl.codification.ChromosomeFixer;
import xfuzzy.xfghl.codification.ChromosomeTester;
import xfuzzy.xfghl.codification.DoubleChromosome;
import xfuzzy.xfghl.codification.Encoder;
import xfuzzy.xfghl.codification.EncodingSymbols;
import xfuzzy.xfghl.codification.TypeErrorChromosome;
import xfuzzy.xfghl.model.XfghlConfig;
import xfuzzy.xfghl.population.Population;

public class PseudoRandomPopulationGenerator /*extends PopulationGenerator*/ {

	private Random random;
	private int size;
	
	public PseudoRandomPopulationGenerator(long seed)  {
		
		this.random = new Random(seed);
		this.size = -1;
	}
	
	public PseudoRandomPopulationGenerator(long seed, int sizePopulation)  {
		
		this.random = new Random(seed);
		this.size = sizePopulation;
	}
	
	public PseudoRandomPopulationGenerator(Random random)  {
		
		this.random = random;
	}

	public Random getRandom() {
		return random;
	}

	public void setRandom(Random random) {
		this.random = random;
	}
	
	public Population generarPoblacion(XfghlConfig config)  {
		
		// poblacion de 6 entradas sin control
		List<DoubleChromosome> individuos = new ArrayList<DoubleChromosome>();
		List<Integer> variables = null;
		DoubleChromosome nuevo = null;
		int longitud_estructura = config.getnumVarEnt() + (config.getnumVarEnt() - 1);
		int [] nuevas_variables = null;
		char [] nueva_estructura = null;
		int indice = -1;
		boolean repeated = false;
		String canonic = "";
		// se generan un numero de individuos igual a la poblacion inicial
		for (int index = 0; index < this.size; index++)  {
			 repeated = true;
			 while (repeated == true)  {
				 repeated = false;
				 // se crean las variables disponibles
				 variables = new ArrayList<Integer>();
				 for (int i = 0; i < config.getnumVarEnt(); i++)
					  variables.add(new Integer(i));
				 nuevas_variables = new int[config.getnumVarEnt()];
				 // se crea el orden de las variables aleatoriamente
				 for (int index_var = 0; index_var < config.getnumVarEnt(); index_var++)  {
					  indice = this.random.nextInt(variables.size());
					  nuevas_variables[index_var] = variables.remove(indice);
				 }
				 // se crea la estructura con sus partes fijas (duda)
				 // si se hace aleatorio, en la reparacion de cromosomas se arregla
				 nueva_estructura = new char[longitud_estructura];
				 nueva_estructura[0] = EncodingSymbols.moduleSymbol;
				 nueva_estructura[longitud_estructura - 1] = EncodingSymbols.variableSymbol;
				 nueva_estructura[longitud_estructura - 2] = EncodingSymbols.variableSymbol;
				 // las partes no fijas se deciden aleatoriamente
				 double valor = 0.0;
				 for (int index_struc = 1; index_struc < longitud_estructura - 2; index_struc++)  {
					  valor = this.random.nextDouble();
					  if (valor > 0.5)
						  nueva_estructura[index_struc] = EncodingSymbols.moduleSymbol;
					  else
						  nueva_estructura[index_struc] = EncodingSymbols.variableSymbol;
				 }
				 nuevo = new DoubleChromosome(config.getnumVarEnt());
				 nuevo.setEstructura(nueva_estructura);
				 nuevo.setVariables(nuevas_variables);
				 nuevo.setNumModulos(config.getnumVarEnt() - 1);
				 // se comprueba que todos los cromosomas sean correctos; si no lo son, se reparan
				 TypeErrorChromosome error = null;
				 error = ChromosomeTester.isValid(nuevo); 
				 while (error != null)  {
					 ChromosomeFixer.reparar(error, nuevo, config);
					 error = ChromosomeTester.isValid(nuevo);
				 }
				 
				 canonic = Encoder.generarCanonico(nuevo);
				 for (DoubleChromosome chro : individuos)  {
					  if (chro.getCanonic().compareTo(canonic) == 0)  {
						  repeated = true;
						  break;
					  }
				 }
			 }
			 nuevo.setCanonic(canonic);
			 individuos.add(nuevo);
		}
		
		return new Population(individuos);
	}

}
